//
//      ┏┛ ┻━━━━━┛ ┻┓
//      ┃　　　　　　 ┃
//      ┃　　　━　　　┃
//      ┃　┳┛　  ┗┳　┃
//      ┃　　　　　　 ┃
//      ┃　　　┻　　　┃
//      ┃　　　　　　 ┃
//      ┗━┓　　　┏━━━┛
//        ┃　　　┃   神兽保佑
//        ┃　　　┃   代码无BUG！
//        ┃　　　┗━━━━━━━━━┓
//        ┃　　　　　　　    ┣┓
//        ┃　　　　         ┏┛
//        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
//          ┃ ┫ ┫   ┃ ┫ ┫/Users/john/Desktop/cftp/ftpclient.c
//          ┗━┻━┛   ┗━┻━┛
//
// Created by john on 2020/2/5. qq 1612163290
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ftpclient.h"
#include "socketutil.h"

static int m_socket_cmd;
static int m_socket_data;
static char m_send_buffer[1024];
static char m_recv_buffer[1024];

static int ftp_send_command(char *cmd){
    int ret;
    ret= socket_send(m_socket_cmd,cmd,(int)strlen(cmd));
    if(ret<0)
    {
        printf("failed to send command: %s",cmd);
        return 0;
    }
    printf("send:%s",cmd);
    return 1;
}

static int ftp_recv_respond(char *resp,int len){
    int ret;
    int off;
    len -=1;
    for(off=0;off<len;off+=ret)//接收len次
    {
        ret=socket_recv(m_socket_cmd,&resp[off],1);//一个字节一个字节接收
        if(ret<0)
        {
            printf("recv respond error (ret=%d)\r\n",ret);
            return 0;
        }
        if(resp[off]=='\n')
        {
            break;
        }
    }
    resp[off+1]=0;
    printf("respond:%s",resp);
    return atoi(resp);
}

static int ftp_enter_pasv(char *ipaddr,int *port)
{
    int ret;
    char *find;
    int a,b,c,d;
    int pa,pb;
    ret = ftp_send_command("PASV\r\n");
    if(ret!=1)
    {
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer,1024);
    if(ret!=227)
    {
        return 0;
    }

    find = strrchr(m_recv_buffer,'{');

    sscanf(find,"(%d,%d,%d,%d,%d,%d)", &a, &b, &c, &d, &pa, &pb);
    sprintf(ipaddr, "%d.%d.%d.%d", a, b, c, d);
    *port = pa * 256 + pb;
    return 1;

}

int ftp_upload(char *name,void *buf,int len)
{
    int  ret;
    char ipaddr[32];
    int  port;

    //Query data address
    ret=ftp_enter_pasv(ipaddr, &port);
    if(ret != 1)
    {
        return 0;
    }
    ret=socket_connect(m_socket_data, ipaddr, port);
    if(ret != 1)
    {
        return 0;
    }
    //Preparing for upload
    sprintf(m_send_buffer, "STOR %s\r\n", name);
    ret = ftp_send_command(m_send_buffer);
    if(ret != 1)
    {
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 150)
    {
        socket_close(m_socket_data);
        return 0;
    }

    //Start uploading
    ret = socket_send(m_socket_data, buf, len);
    if(ret != len)
    {
        printf("send data error!\r\n");
        socket_close(m_socket_data);
        return 0;
    }
    socket_close(m_socket_data);

    //Upload complete, wait for response
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    return (ret==226);
}

int ftp_download(char *name,void *buf,int len)
{
    int   i;
    int   ret;
    char  ipaddr[32];
    int   port;

    //Query data address
    ret = ftp_enter_pasv(ipaddr, &port);
    if(ret != 1)
    {
        return 0;
    }
    //Connect data ports
    ret = socket_connect(m_socket_data, ipaddr, port);
    if(ret != 1)
    {
        printf("failed to connect data port\r\n");
        return 0;
    }

    //Ready to download
    sprintf(m_send_buffer, "RETR %s\r\n", name);
    ret = ftp_send_command(m_send_buffer);
    if(ret != 1)
    {
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 150)
    {
        socket_close(m_socket_data);
        return 0;
    }

    //Start downloading and the server will automatically close the connection after reading the data
    for(i=0; i<len; i+=ret)
    {
        ret = socket_recv(m_socket_data, ((char *)buf) + i, len);
        printf("download %d/%d.\r\n", i + ret, len);
        if(ret < 0)
        {
            printf("download was interrupted.\r\n");
            break;
        }
    }
    //Download complete
    printf("download %d/%d bytes complete.\r\n", i, len);
    socket_close(m_socket_data);
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    return (ret==226);
}

int ftp_filesize(char *name){
    int ret;
    int size;
    sprintf(m_send_buffer,"SIZE %s\r\n",name);
    ret = ftp_send_command(m_send_buffer);
    if(ret != 1)
    {
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 213)
    {
        return 0;
    }
    size = atoi(m_recv_buffer + 4);
    return size;
}

int ftp_login(char * addr,int port,char *username,char *password){
    int ret;
    printf("connect...\r\n");
    ret = socket_connect(m_socket_cmd, addr, port);
    if(ret != 1)
    {
        printf("connect server failed!\r\n");
        return 0;
    }
    printf("connect ok.\r\n");
    //Waiting for Welcome Message
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 220)
    {
        printf("bad server, ret=%d!\r\n", ret);
        socket_close(m_socket_cmd);
        return 0;
    }

    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 220)
    {
        printf("bad server, ret=%d!\r\n", ret);
        socket_close(m_socket_cmd);
        return 0;
    }

    printf("login...\r\n");
    //Send USER
    sprintf(m_send_buffer, "USER %s\r\n", username);
    ret = ftp_send_command(m_send_buffer);
    if(ret != 1)
    {
        socket_close(m_socket_cmd);
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
//    if(ret != 331)
//    {
//        socket_close(m_socket_cmd);
//        return 0;
//    }

    //Send PASS
    sprintf(m_send_buffer, "PASS %s\r\n", password);
    ret = ftp_send_command(m_send_buffer);
    if(ret != 1)
    {
        socket_close(m_socket_cmd);
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 230)
    {
        socket_close(m_socket_cmd);
        return 0;
    }
    printf("login success.\r\n");

    //Set to binary mode
    ret = ftp_send_command("TYPE I\r\n");
    if(ret != 1)
    {
        socket_close(m_socket_cmd);
        return 0;
    }
    ret = ftp_recv_respond(m_recv_buffer, 1024);
    if(ret != 200)
    {
        socket_close(m_socket_cmd);
        return 0;
    }
    return 1;
}

void ftp_quit(void)
{
    ftp_send_command("QUIT\r\n");
    socket_close(m_socket_cmd);
}

void ftp_init(void)
{
    m_socket_cmd=socket_create();
    m_socket_data=socket_create();
}

